/*
 * =====================================================================================
 *
 *       Filename:  cl_socket_addr_in4.cxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  03/24/2011 06:19:53 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Chen Ken (Ken), zlchen.ken@gmail.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <cstring>
#include "cl_socket_addr_in4.hxx"
#include "cl_implicit_cast.hxx"

namespace neo
{
using namespace std;

CLSocketAddrIn4::CLSocketAddrIn4(const string& host, int port, CLSocketType type) 
{
  memset(&m_sockAddr, 0, sizeof(m_sockAddr));
  initAddr(host, port, type);
}
  
void CLSocketAddrIn4::initAddr(const string& host, int port, CLSocketType type)
{
  struct addrinfo hints;
  char portStr[10];
  const char* pHost = NULL;
  const char* pPort = NULL;
  int gaierr;

  ::bzero(&hints, sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = clSocketTypeToNativeType(type);
  if(port > 0)
  {
  	::snprintf(portStr, sizeof(portStr), "%d", port);
  	pPort = portStr;
  }

  if(!host.empty())
  {
    pHost = host.c_str();
  }

  struct addrinfo* addrs = NULL;
  if((gaierr = ::getaddrinfo(pHost, pPort, &hints, &addrs)) != 0)
  {
  	// KENTODO..gai_strerror(gaierr)
  	return;
  }

  if(addrs != NULL)
  {
  	::memmove(&m_sockAddr, addrs->ai_addr, addrs->ai_addrlen);
  }

  ::freeaddrinfo(addrs);
}

CLSocketAddrIn4::CLSocketAddrIn4(const struct sockaddr* addr) 
{
  ::memmove(&m_sockAddr, addr, getSize());
}

CLSocketAddrIn4::~CLSocketAddrIn4() 
{
}

CLSocketAddr* CLSocketAddrIn4::doClone(void) const 
{
  return new CLSocketAddrIn4(*this);
}

int CLSocketAddrIn4::getFamily(void) const 
{
  return AF_INET;
}

size_t CLSocketAddrIn4::getSize(void) const 
{
  return sizeof(m_sockAddr);
}

const struct sockaddr* CLSocketAddrIn4::getAddress(void) const 
{
  return (const struct sockaddr*)(&m_sockAddr);
}

bool CLSocketAddrIn4::doIsValid(void) const 
{
  return ((int)(m_sockAddr.sin_addr.s_addr) != -1);
}

const string CLSocketAddrIn4::doToString(void) const
{
	char buf[64];
  char host[INET_ADDRSTRLEN + 1] = "INVALID";
  ::inet_ntop(AF_INET, &m_sockAddr.sin_addr, host, sizeof(host));
  snprintf(buf, sizeof(buf), "%s:%u", host, ntohs(m_sockAddr.sin_port));
	buf[63] = '\0';
  return buf;
}

} // neo

